home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / unarced / graphics / anim / loadpict.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  12KB  |  311 lines

  1.  
  2. /** LoadPict.c **************************************************************
  3.  *
  4.  * Load an ILBM raster image file into an existing bitmap.
  5.  * This is a slightly modified version of ReadPict.c dated 23-Jan-86.
  6.  * 
  7.  * Modified by Gary Bonham, Sparta, Inc.  25 Apr 1986
  8.  * Further mods on 26-Jul-86 to permit it to read only the initial
  9.  * bitmap for ANIM files.  Use LoadAnim.c to read entire anim files.
  10.  *
  11.  * By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
  12.  * This software is in the public domain.
  13.  *
  14.  * USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF READER.
  15.  *
  16.  * The IFF reader portion is essentially a recursive-descent parser.
  17.  ****************************************************************************/
  18.  
  19. #define LOCAL   static
  20.  
  21. #include "functions.h"
  22. #include "intuall.h"
  23. #include "libraries/dos.h"
  24. #include "libraries/dosextens.h"
  25. #include "ilbm.h"
  26. #include "readpict.h"
  27. #include "putanim.h"
  28.  
  29. /* This example's max number of planes in a bitmap. Could use MaxAmDepth. */
  30. #define EXDepth 5
  31. #define maxColorReg (1<<EXDepth)
  32. #define MIN(a,b) ((a)<(b)?(a):(b))
  33.  
  34. #define SafeFreeMem(p,q) {if(p)FreeMem(p,q);}
  35. #define GetANHD(context,anHdr) \
  36.    IFFReadBytes(context,(BYTE *)anHdr,(long)sizeof(AnimationHeader))
  37.  
  38. /* Define the size of a temporary buffer used in unscrambling the ILBM rows.*/
  39. #define bufSz 512
  40.  
  41. extern int Pop;
  42.  
  43. /*------------ ILBM reader -----------------------------------------------*/
  44. /* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file.
  45.  * We allocate one of these on the stack for every LIST or FORM encountered
  46.  * in the file and use it to hold BMHD & CMAP properties. We also allocate
  47.  * an initial one for the whole file.
  48.  * We allocate a new GroupContext (and initialize it by OpenRIFF or
  49.  * OpenRGroup) for every group (FORM, CAT, LIST, or PROP) encountered. It's
  50.  * just a context for reading (nested) chunks.
  51.  *
  52.  * If we were to scan the entire example file outlined below:
  53.  *    reading          proc(s)                new               new
  54.  *
  55.  * --whole file--   ReadPicture+ReadIFF   GroupContext        ILBMFrame
  56.  * CAT              ReadICat                GroupContext
  57.  *   LIST           GetLiILBM+ReadIList       GroupContext        ILBMFrame
  58.  *     PROP ILBM    GetPrILBM                   GroupContext
  59.  *       CMAP       GetCMAP
  60.  *       BMHD       GetBMHD
  61.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  62.  *       BODY       GetBODY
  63.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  64.  *       BODY       GetBODY
  65.  *   FORM ILBM      GetFoILBM                 GroupContext        ILBMFrame
  66.  */
  67.  
  68. /* NOTE: For a small version of this program, set Fancy to 0.
  69.  * That'll compile a program that reads a single FORM ILBM in a file, which
  70.  * is what DeluxePaint produces. It'll skip all LISTs and PROPs in the input
  71.  * file. It will, however, look inside a CAT for a FORM ILBM.
  72.  * That's suitable for 90% of the uses.
  73.  *
  74.  * For a fancier version that handles LISTs and PROPs, set Fancy to 1.
  75.  * That'll compile a program that dives into a LIST, if present, to read
  76.  * the first FORM ILBM. E.g. a DeluxePrint library of images is a LIST of
  77.  * FORMs ILBM.
  78.  *
  79.  * For an even fancier version, set Fancy to 2. That'll compile a program
  80.  * that dives into non-ILBM FORMs, if present, looking for a nested FORM ILBM.
  81.  * E.g. a DeluxeVideo C.S. animated object file is a FORM ANBM containing a
  82.  * FORM ILBM for each image frame. */
  83. #define Fancy  2
  84.  
  85. /* Global access to client-provided pointers.*/
  86. LOCAL Allocator *gAllocator = NULL;
  87. LOCAL struct BitMap *gBM = NULL;   /* client's bitmap.*/
  88. LOCAL ILBMFrame *giFrame = NULL;   /* "client frame".*/
  89.  
  90. /** GetFoILBM() *************************************************************
  91.  *
  92.  * Called via ReadPicture to handle every FORM encountered in an IFF file.
  93.  * Reads FORMs ILBM and skips all others.
  94.  * Inside a FORM ILBM, it stops once it reads a BODY. It complains if it
  95.  * finds no BODY or if it has no BMHD to decode the BODY.
  96.  *
  97.  * Once we find a BODY chunk, we'll allocate the BitMap and read the image.
  98.  *
  99.  ****************************************************************************/
  100. LOCAL BYTE bodyBuffer[bufSz];
  101. IFFP GetFoILBM(parent)
  102. GroupContext *parent;
  103. {
  104.    /*compilerBug register*/ IFFP iffp;
  105.    PLANEPTR plane0; /* GB - 25 apr 86 */
  106.    GroupContext formContext;
  107.    AnimationHeader animHdr;
  108.    ILBMFrame ilbmFrame;      /* only used for non-clientFrame fields.*/
  109.    register int i;
  110.    LONG plsize;   /* Plane size in bytes. */
  111.    long nPlanes; /* number of planes in our display image */
  112.  
  113.    /* Handle a non-ILBM FORM. */
  114.    if (parent->subtype != ID_ILBM) {
  115. #if Fancy >= 2
  116.       /* Open a non-ILBM FORM and recursively scan it for ILBMs.*/
  117.       iffp = OpenRGroup(parent, &formContext);
  118.       CheckIFFP();
  119.       do {
  120.           iffp = GetF1ChunkHdr(&formContext);
  121. /*          if (iffp == IFF_DONE) iffp = IFF_OKAY;*/
  122.       } while (iffp >= IFF_OKAY);
  123.       if (iffp == END_MARK)  iffp = IFF_DONE;   /* then continue scanning the file */
  124.       CloseRGroup(&formContext);
  125.       return(iffp);
  126. #else
  127.       return(IFF_OKAY); /* Just skip this FORM and keep scanning the file.*/
  128. #endif
  129.    }
  130.  
  131.    ilbmFrame = *(ILBMFrame *)parent->clientFrame;
  132.    iffp = OpenRGroup(parent, &formContext);
  133.    CheckIFFP();
  134.  
  135.    do {
  136.       switch (iffp = GetFChunkHdr(&formContext)) {
  137.          case ID_ANHD: {
  138.         iffp = GetANHD(&formContext, &animHdr);
  139.             Pop = animHdr.operation;
  140.         break;
  141.          }
  142.          case ID_BMHD: {
  143.             ilbmFrame.foundBMHD = TRUE;
  144.             iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr);
  145.             break;
  146.          }
  147.          case ID_CMAP: {
  148.             ilbmFrame.nColorRegs = maxColorReg;  /* we have room for this many */
  149.             iffp = GetCMAP(&formContext, (WORD *)&ilbmFrame.colorMap[0]
  150.                    , &ilbmFrame.nColorRegs);
  151.                                           /* was &ilbmFrame.colorMap, (fixed) robp. */
  152.             break;
  153.          }
  154.          case ID_BODY: {
  155.             if (!ilbmFrame.foundBMHD)  return(BAD_FORM);   /* No BMHD chunk! */
  156.             nPlanes = MIN(ilbmFrame.bmHdr.nPlanes, EXDepth);
  157.             plane0 = gBM->Planes[0]; /* save ptr to existing bitmap  - GB 25 apr 86*/
  158.             InitBitMap(gBM,(long)nPlanes,(long)ilbmFrame.bmHdr.pageWidth
  159.                       ,(long)ilbmFrame.bmHdr.pageHeight);
  160.             plsize = RowBytes((long)ilbmFrame.bmHdr.pageWidth)
  161.                             * (long)ilbmFrame.bmHdr.pageHeight;
  162.               /* Assume all planes were allocated contiguously.
  163.                * Here we partition up the memory for the required bitmaps
  164.                * on the assumption that there was enough allocated.
  165.                */
  166.             if (plane0) {  /* GB - 25 apr 86 */
  167.                for (i = 0; i < nPlanes; i++) gBM->Planes[i] = plane0 + plsize*i;
  168.                iffp = GetBODY(&formContext,gBM,0L,&ilbmFrame.bmHdr
  169.                       ,bodyBuffer,bufSz);
  170.                *giFrame = ilbmFrame;  /* Copy fields to client's frame.*/
  171.                if (iffp == IFF_OKAY) iffp = IFF_DONE;   /* Eureka */
  172.             }
  173.             else iffp = CLIENT_ERROR;   /* RAM not allocated for the bitmap */
  174.             break;
  175.          }
  176.          case END_MARK: {
  177.             Pop = 0;
  178.             iffp = IFF_DONE; 
  179.             break;
  180.          } /* No BODY chunk! */
  181.       }
  182.    } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
  183.                                * subroutine returned IFF_OKAY (no errors).*/
  184.  
  185.    if (iffp != IFF_DONE)  return(iffp);
  186.  
  187.    /* If we get this far, there were no errors. */
  188.    CloseRGroup(&formContext);
  189.    return(iffp);
  190. }
  191.  
  192. /** Notes on extending GetFoILBM ********************************************
  193.  *
  194.  * To read more kinds of chunks, just add clauses to the switch statement.
  195.  * To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to
  196.  * the switch statement in GetPrILBM, too.
  197.  *
  198.  * To read a FORM type that contains a variable number of data chunks--e.g.
  199.  * a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with
  200.  * an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK
  201.  * case do whatever cleanup you need.
  202.  *
  203.  ****************************************************************************/
  204.  
  205. /** GetPrILBM() *************************************************************
  206.  *
  207.  * Called via ReadPicture to handle every PROP encountered in an IFF file.
  208.  * Reads PROPs ILBM and skips all others.
  209.  *
  210.  ****************************************************************************/
  211. #if Fancy
  212. IFFP GetPrILBM(parent)
  213. GroupContext *parent;
  214. {
  215.    /*compilerBug register*/ IFFP iffp;
  216.    GroupContext propContext;
  217.    ILBMFrame *ilbmFrame = (ILBMFrame *)parent->clientFrame;
  218.  
  219.    if (parent->subtype != ID_ILBM) return(IFF_OKAY);   /* just continue scaning the file */
  220.  
  221.    iffp = OpenRGroup(parent, &propContext);
  222.    CheckIFFP();
  223.  
  224.    do {
  225.       switch (iffp = GetPChunkHdr(&propContext)) {
  226.          case ID_BMHD: {
  227.             ilbmFrame->foundBMHD = TRUE;
  228.             iffp = GetBMHD(&propContext, &ilbmFrame->bmHdr);
  229.             break;
  230.          }
  231.          case ID_CMAP: {
  232.             ilbmFrame->nColorRegs = maxColorReg; /* we have room for this many */
  233.             iffp = GetCMAP(&propContext,(WORD *)&ilbmFrame->colorMap,&ilbmFrame->nColorRegs);
  234.             break;
  235.          }
  236.       }
  237.    } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
  238.                                  * subroutine returned IFF_OKAY (no errors).*/
  239.  
  240.    CloseRGroup(&propContext);
  241.    return(iffp == END_MARK ? IFF_OKAY : iffp);
  242. }
  243. #endif
  244.  
  245. /** GetLiILBM() *************************************************************
  246.  *
  247.  * Called via ReadPicture to handle every LIST encountered in an IFF file.
  248.  *
  249.  ****************************************************************************/
  250. #if Fancy
  251. IFFP GetLiILBM(parent) 
  252. GroupContext *parent;
  253. {
  254.    ILBMFrame newFrame;   /* allocate a new Frame */
  255.    newFrame = *(ILBMFrame *)parent->clientFrame;  /* copy parent frame */
  256.    return( ReadIList(parent, (ClientFrame *)&newFrame) );
  257. }
  258. #endif
  259.  
  260. /** ReadPicture() **********************************************************/
  261. IFFP ReadPicture(file, bm, iFrame, allocator)
  262. LONG file;
  263. struct BitMap *bm;
  264. ILBMFrame *iFrame;   /* Top level "client frame".*/
  265.  
  266.    /* **** ERROR IN SOURCE CODE, WAS jFrame, now iFrame */
  267.    /* fixed */
  268.  
  269. Allocator *allocator;
  270. {
  271.    IFFP iffp = IFF_OKAY;
  272. #if Fancy
  273.    iFrame->clientFrame.getList = GetLiILBM;
  274.    iFrame->clientFrame.getProp = GetPrILBM;
  275. #else
  276.    iFrame->clientFrame.getList = SkipGroup;
  277.    iFrame->clientFrame.getProp = SkipGroup;
  278. #endif
  279.    iFrame->clientFrame.getForm = GetFoILBM;
  280.    iFrame->clientFrame.getCat  = ReadICat ;
  281.  
  282.    /* Initialize the top-level client frame's property settings to the
  283.     * program-wide defaults. This example just records that we haven't read
  284.     * any BMHD property or CMAP color registers yet. For the color map, that
  285.     * means the default is to leave the machine's color registers alone.
  286.     * If you want to read a property like GRAB, init it here to (0, 0). */
  287.    iFrame->foundBMHD  = FALSE;
  288.    iFrame->nColorRegs = 0;
  289.  
  290.    gAllocator = allocator;
  291.    gBM = bm;
  292.    giFrame = iFrame;
  293.   /* Store a pointer to the client's frame in a global variable so that
  294.    * GetFoILBM can update client's frame when done.  Why do we have so
  295.    * many frames & frame pointers floating around causing confusion?
  296.    * Because IFF supports PROPs which apply to all FORMs in a LIST,
  297.    * unless a given FORM overrides some property.  
  298.    * When you write code to read several FORMs,
  299.    * it is ssential to maintain a frame at each level of the syntax
  300.    * so that the properties for the LIST don't get overwritten by any
  301.    * properties specified by individual FORMs.
  302.    * We decided it was best to put that complexity into this one-FORM example,
  303.    * so that those who need it later will have a useful starting place.
  304.    */
  305.  
  306.    iffp = ReadIFF(file, (ClientFrame *)iFrame);
  307.    return(iffp);
  308. }
  309.  
  310.  
  311.